package it.mp.multitask.utility.music;

import it.mp.multitask.R;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;

import com.android.music.IMediaPlaybackService;

import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.provider.MediaStore;
import android.util.Log;

public class MusicUtils {
	public static IMediaPlaybackService sService = null;
	private static HashMap<Context, ServiceBinder> sConnectionMap = new HashMap<Context, ServiceBinder>();
	private static final Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
	private static final BitmapFactory.Options sBitmapOptions = new BitmapFactory.Options();
	
	static {
		sBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565;
		sBitmapOptions.inDither = false;
	}
	
	public static boolean bindToService(Context context) {
		Intent i = new Intent();
		i.setPackage("com.android.music");
		i.setClassName("com.android.music", "com.android.music.MediaPlaybackService");
		context.startService(i);
		ServiceBinder sb = new ServiceBinder();
		sConnectionMap.put(context, sb);
		return context.bindService(i, sb, 0);
	}
	public static void unbindFromService(Context context) {
		ServiceBinder sb = (ServiceBinder) sConnectionMap.remove(context);
		if (sb == null) {
			Log.e("MusicUtils", "Trying to unbind for unknown Context");
			return;
		}
		context.unbindService(sb);
	}
	private static class ServiceBinder implements ServiceConnection {

		public void onServiceConnected(ComponentName className, android.os.IBinder service) {
			sService = IMediaPlaybackService.Stub.asInterface(service);

		}

		public void onServiceDisconnected(ComponentName className) {

			sService = null;
		}
	}

	 public static Bitmap getArtworkQuick(Context context, int album_id, int w, int h) {
	        // NOTE: There is in fact a 1 pixel frame in the ImageView used to
	        // display this drawable. Take it into account now, so we don't have to
	        // scale later.
	        w -= 2;
	        h -= 2;
	        ContentResolver res = context.getContentResolver();
	        Uri uri = ContentUris.withAppendedId(sArtworkUri, album_id);
	        if (uri != null) {
	            ParcelFileDescriptor fd = null;
	            try {
	                fd = res.openFileDescriptor(uri, "r");
	                int sampleSize = 1;
	                
	                // Compute the closest power-of-two scale factor 
	                // and pass that to sBitmapOptionsCache.inSampleSize, which will
	                // result in faster decoding and better quality
	                sBitmapOptions.inJustDecodeBounds = true;
	                BitmapFactory.decodeFileDescriptor(
	                        fd.getFileDescriptor(), null, sBitmapOptions);
	                int nextWidth = sBitmapOptions.outWidth >> 1;
	                int nextHeight = sBitmapOptions.outHeight >> 1;
	                while (nextWidth>w && nextHeight>h) {
	                    sampleSize <<= 1;
	                    nextWidth >>= 1;
	                    nextHeight >>= 1;
	                }

	                sBitmapOptions.inSampleSize = sampleSize;
	                sBitmapOptions.inJustDecodeBounds = false;
	                Bitmap b = BitmapFactory.decodeFileDescriptor(
	                        fd.getFileDescriptor(), null, sBitmapOptions);

	                if (b != null) {
	                    // finally rescale to exactly the size we need
	                    if (sBitmapOptions.outWidth != w || sBitmapOptions.outHeight != h) {
	                        Bitmap tmp = Bitmap.createScaledBitmap(b, w, h, true);
	                        b.recycle();
	                        b = tmp;
	                    }
	                }
	                
	                return b;
	            } catch (FileNotFoundException e) {
	            } finally {
	                try {
	                    if (fd != null)
	                        fd.close();
	                } catch (IOException e) {
	                }
	            }
	        }
	        return null;
	    }
	
	public static Bitmap getArtwork(Context context, int album_id) {

		if (album_id < 0) {
			// This is something that is not in the database, so get the album
			// art directly
			// from the file.
			Bitmap bm = getArtworkFromFile(context, null, -1);
			if (bm != null) {
				return bm;
			}
			return getDefaultArtwork(context);
		}

		ContentResolver res = context.getContentResolver();
		Uri uri = ContentUris.withAppendedId(sArtworkUri, album_id);
		if (uri != null) {
			InputStream in = null;
			try {
				in = res.openInputStream(uri);
				return BitmapFactory.decodeStream(in, null, sBitmapOptions);
			} catch (FileNotFoundException ex) {
				// The album art thumbnail does not actually exist. Maybe the
				// user deleted it, or
				// maybe it never existed to begin with.
				Bitmap bm = getArtworkFromFile(context, null, album_id);
				if (bm != null) {
					// Put the newly found artwork in the database.
					// Note that this shouldn't be done for the "unknown" album,
					// but if this method is called correctly, that won't
					// happen.

					// first write it somewhere
					String file = Environment.getExternalStorageDirectory() + "/albumthumbs/" + String.valueOf(System.currentTimeMillis());
					if (ensureFileExists(file)) {
						try {
							OutputStream outstream = new FileOutputStream(file);
							if (bm.getConfig() == null) {
								bm = bm.copy(Bitmap.Config.RGB_565, false);
								if (bm == null) {
									return getDefaultArtwork(context);
								}
							}
							boolean success = bm.compress(Bitmap.CompressFormat.JPEG, 75, outstream);
							outstream.close();
							if (success) {
								ContentValues values = new ContentValues();
								values.put("album_id", album_id);
								values.put("_data", file);
								Uri newuri = res.insert(sArtworkUri, values);
								if (newuri == null) {
									// Failed to insert in to the database. The
									// most likely
									// cause of this is that the item already
									// existed in the
									// database, and the most likely cause of
									// that is that
									// the album was scanned before, but the
									// user deleted the
									// album art from the sd card.
									// We can ignore that case here, since the
									// media provider
									// will regenerate the album art for those
									// entries when
									// it detects this.
									success = false;
								}
							}
							if (!success) {
								File f = new File(file);
								f.delete();
							}
						} catch (FileNotFoundException e) {
							Log.e("MusicUtils", "error creating file", e);
						} catch (IOException e) {
							Log.e("MusicUtils", "error creating file", e);
						}
					}
				} else {
					bm = getDefaultArtwork(context);
				}
				return bm;
			} finally {
				try {
					if (in != null) {
						in.close();
					}
				} catch (IOException ex) {
				}
			}
		}

		return null;
	}

	private static Bitmap getArtworkFromFile(Context context, Uri uri, int albumid) {
		Bitmap bm = null;
		byte[] art = null;
		String path = null;

		// try reading embedded artwork
		if (uri == null) {
			try {
				int curalbum = sService.getAlbumId();
				if (curalbum == albumid || albumid < 0) {
					path = sService.getPath();
					if (path != null) {
						uri = Uri.parse(path);
					}
				}
			} catch (RemoteException ex) {
			}
		}
		if (uri == null) {
			if (albumid >= 0) {
				Cursor c = query(context, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Audio.Media._ID, MediaStore.Audio.Media.ALBUM},
						MediaStore.Audio.Media.ALBUM_ID + "=?", new String[]{String.valueOf(albumid)}, null);
				if (c != null) {
					c.moveToFirst();
					if (!c.isAfterLast()) {
						int trackid = c.getInt(0);
						uri = ContentUris.withAppendedId(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, trackid);
					}
					if (c.getString(1).equals("")) {
						albumid = -1;
					}
					c.close();
				}
			}
		}

		if (art != null) {
			try {
				// get the size of the bitmap
				BitmapFactory.Options opts = new BitmapFactory.Options();
				opts.inJustDecodeBounds = true;
				opts.inSampleSize = 1;
				BitmapFactory.decodeByteArray(art, 0, art.length, opts);

				// request a reasonably sized output image
				// TODO: don't hardcode the size
				while (opts.outHeight > 320 || opts.outWidth > 320) {
					opts.outHeight /= 2;
					opts.outWidth /= 2;
					opts.inSampleSize *= 2;
				}

				// get the image for real now
				opts.inJustDecodeBounds = false;
				bm = BitmapFactory.decodeByteArray(art, 0, art.length, opts);
			} catch (Exception e) {
			}
		}
		return bm;
	}

	public static Cursor query(Context context, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
		try {
			ContentResolver resolver = context.getContentResolver();
			if (resolver == null) {
				return null;
			}
			return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
		} catch (UnsupportedOperationException ex) {
			return null;
		}

	}

	private static Bitmap getDefaultArtwork(Context context) {
		BitmapFactory.Options opts = new BitmapFactory.Options();
		opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
		return BitmapFactory.decodeStream(context.getResources().openRawResource(R.drawable.play_button), null, opts);
	}

	private static boolean ensureFileExists(String path) {
		File file = new File(path);
		if (file.exists()) {
			return true;
		} else {
			// we will not attempt to create the first directory in the path
			// (for example, do not create /sdcard if the SD card is not
			// mounted)
			int secondSlash = path.indexOf('/', 1);
			if (secondSlash < 1)
				return false;
			String directoryPath = path.substring(0, secondSlash);
			File directory = new File(directoryPath);
			if (!directory.exists())
				return false;
			file.getParentFile().mkdirs();
			try {
				return file.createNewFile();
			} catch (IOException ioe) {
				Log.e("MusicUtils", "File creation failed", ioe);
			}
			return false;
		}
	}
}
